package com.example.redis.statemachine.service;

import com.example.redis.statemachine.model.OrderDTO;
import com.example.redis.statemachine.enums.OrderStatusChangeEventEnum;
import com.example.redis.statemachine.enums.OrderStatusEnum;
import com.example.redis.statemachine.consts.CommonConstants;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;

/**
 * 业务接口
 *
 * @description:
 * @author: bo
 * @create: 2024-03-18 14:06
 */
@Service
@Slf4j
public class OrderService {

    @Resource
    private StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;

    @Resource
    private StateMachinePersister<OrderStatusEnum, OrderStatusChangeEventEnum, String> stateMachineRedisPersister;

    private long id = 1L;

    private Map<Long, OrderDTO> orders = Maps.newConcurrentMap();


    public OrderDTO create() {
        OrderDTO OrderDTO = new OrderDTO();
        OrderDTO.setStatus(OrderStatusEnum.WAIT_PAYMENT.getKey());
        OrderDTO.setOrderId(id++);
        orders.put(OrderDTO.getOrderId(), OrderDTO);
        System.out.println("订单创建成功:" + OrderDTO.toString());
        return OrderDTO;
    }


    public OrderDTO pay(long id) {
        OrderDTO OrderDTO = orders.get(id);
        System.out.println("尝试支付，订单号：" + id);
        if (!sendEvent(OrderStatusChangeEventEnum.PAYED, OrderDTO, CommonConstants.PAY_TRANSITION)) {
            System.out.println(" 支付失败, 状态异常，订单号：" + id);
        }
        return orders.get(id);
    }


    public OrderDTO deliver(long id) {
        OrderDTO OrderDTO = orders.get(id);
        System.out.println(" 尝试发货，订单号：" + id);
        if (!sendEvent(OrderStatusChangeEventEnum.DELIVERY, OrderDTO,CommonConstants.DELIVERY_TRANSITION )) {
            System.out.println(" 发货失败，状态异常，订单号：" + id);
        }
        return orders.get(id);
    }


    public OrderDTO receive(long id) {
        OrderDTO OrderDTO = orders.get(id);
        System.out.println(" 尝试收货，订单号：" + id);
        if (!sendEvent(OrderStatusChangeEventEnum.RECEIVED, OrderDTO,CommonConstants.RECEIVED_TRANSITION )) {
            System.out.println(" 收货失败，状态异常，订单号：" + id);
        }
        return orders.get(id);
    }


    public Map<Long, OrderDTO> getOrders() {
        return orders;
    }


    /**
     * 发送状态
     * @param changeEvent
     * @param order
     * @param key
     * @return
     */
    private synchronized boolean sendEvent(OrderStatusChangeEventEnum changeEvent, OrderDTO order, String key) {
        boolean result = false;
        try {
            //启动状态机
            orderStateMachine.start();
            //尝试恢复状态机状态
            // stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getOrderId()));

            Message message = MessageBuilder.withPayload(changeEvent).setHeader(CommonConstants.ORDER_DTO, order).build();
            //事件执行异常了，依然返回true，无法感知异常
            //解决方案：自己保存异常到数据库或者内存中，进行判断,也可以通过接口：org.springframework.statemachine.StateMachine##getExtendedState方法把执行状态放入这个变量中
            result = orderStateMachine.sendEvent(message);
            if(!result){
                return false;
            }

            //获取到监听的结果信息
            Integer obj = (Integer) orderStateMachine.getExtendedState().getVariables().get(key+ order.getOrderId());
            //操作完成之后,删除本次对应的key信息
            orderStateMachine.getExtendedState().getVariables().remove(key+order.getOrderId());
            //如果事务执行成功，则持久化状态机
            if(Objects.equals(1,Integer.valueOf(obj))){
                //持久化状态机状态
                stateMachineRedisPersister.persist(orderStateMachine, String.valueOf(order.getOrderId()));
            }else {
                //订单执行业务异常
                return false;
            }


        } catch (Exception e) {
            log.error("订单操作失败:{}", e.getMessage());
        } finally {
            orderStateMachine.stop();

            // if (Objects.nonNull(message)) {
            //     OrderDTO OrderDTO = (OrderDTO) message.getHeaders().get("OrderDTO");
            //     if (Objects.nonNull(OrderDTO) && Objects.equals(OrderDTO.getStatus(), OrderStatusEnum.FINISH.getKey())) {
            //         orderStateMachine.stop();
            //     }
            // }
        }
        return result;
    }

}
